package util;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;

/**
 * @ IO类主要功能：为init类作预备工作
 * 包括：
 * (1) 创建文件夹
 * (2) 将我已有的字节文件转换为字符串，也就是将文件读取进字符串列表
 * (3) 将转换完成的字符串写入文件中
 * 核心：编译原始信息文件(即学号-名字的表单)，使其便于以规范格式读入作业系统中
 */
/**
 * IO类是对Java11版本的部分IO功能的封装，以降低开发难度 <br>
 * IO类提供了3个静态方法，并在主函数中提供了使用样例 <br>
 * 
 * 参考资料：<br>
 * https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/file/Files.html
 * <br>
 * https://docs.oracle.com/javase/8/docs/api/java/nio/file/Paths.html
 * 
 */
public class IO {
    // Step. 0
    // 声明一个用来创建、读取和写入的成员变量options数组
    static OpenOption[] options;
    // 在静态代码块中对数组options进行标准初始化：
    // （1）如果传入的表格文件非“只读”，那么瞬间会被truncate清空；如果表格是“只读”的属性，那么这个选项会被直接忽略//附例子
    // q：数据未备份的操作问题：只有表格完全不用时才需要将表格数据一整个干掉。与delete相比，turncate是一个强且高危的方法
    // （2）检验表单是否重复：假如表单不存在的话就即刻创建一个表单，如果想要创建的文件已经存在了，这个动作会被直接忽略
    /**
     * @功能 (1) 它指定了文件创建、打开和读入的方式。 一方面，如果文件已经存在，并且已打开以进行写入访问，则其长度被截断为
     *     0，也就是说这个文件（表格）里的数据将会被整个清空；如果在选项处选择“只读”模式，就会忽视这步操作。 一方面，如果文件不存在，就创建一个新文件
     *     (2) 通过这个代码块对类的初始化，一定程度上可以控制成绩文件传入的规范，也体现了程序的鲁棒性
     */
    static {
        options = new OpenOption[] { StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE };
    }

    // Setp. 1
    /**
     * 读取文件到字符串列表
     * charset：此处文件的信息读入的主要目的是从“让人看懂”到“让计算机看懂”，通俗来说是需要将传入文件中的字节转化为计算机看得懂的16位uni-code字符串
     * 
     * @param file
     * @param cs
     * @return
     * 
     */
    public static List<String> fileToStringList(String file, Charset cs) {
        // 创建一个初始值为空的字符串列表stringList
        List<String> stringList = null;
        try {
            // 用path接口创建一个实例来返回文件的路径字符串
            Path p = Paths.get(file);
            // 用空列stringList来读取传入文件所有行（此时）
            // readAllLines(Path path,Charset cs)可确保当所有字节都已读取,或当出现 I/O 错误或其他运行时异常时关闭文件
            stringList = Files.readAllLines(p, cs);
            // 前面的try块里尝试捕获运行时的错误
        } catch (IOException e) {
            // 假如真的出现了文件创建、读取和写入方面的问题，在catch中会捕获被抛出的I/O错误，并将其打出
            System.err.println(e);
        }
        // 假如运行顺利，则实现字符串列表的读取功能，将文件中的信息逐行读入stringList
        return stringList;
    }

    // Setp. 2
    /**
     * 将字符串写入文件 （字符串的转化工作在step2完成）
     * 
     * @param file
     * @param cs
     * @param content
     */
    public static void stringToFile(String file, Charset cs, String content) {
        try {
            // 获取传入文件路径
            Path p = Paths.get(file);
            // 根据文件的路径索引找到文件，写入文件中的字符序列content
            // 此时文件的创建和打开方式是被确定了的：link-static静态初始化代码块
            Files.writeString(p, content, cs, options);
        } catch (IOException e) {
            // 尝试捕获程序在文件读录上发生的错误并将错误返回
            System.err.println(e);
        }
    }

    // Step. 3
    /**
     * 
     * 创建一个目录，默认递归创建
     * 
     * @param dir
     */

    // 传入一个新文件夹的文件夹名
    // 这个新文件夹名是包含其-tree层次的
    /**
     * String fileName = "/home/janbodnar/docs/memos"; 
     * Path path = Paths.get(fileName); Files.createDirectories(path);
     */
    public static void mkdir(String dir) {
        try {
            // 定位我创建的文件夹的位置
            Path p = Paths.get(dir);
            // 在相应位置创建相应文件夹
            Files.createDirectories(p);
        } catch (Exception e) {
            System.err.println(e);
        }
    }

    public static void main(String[] args) {
        // 测试
        // javac -cp src/ -d dist/ src/util/IO.java
        // java -cp dist/ util.IO tmp/ name-list.csv tmp/name-list-copy.csv
        String tmpDir = "_hw";
        String nameListFile = "name-list.csv";
        String nameListCopyFile = "name-list-copy.csv";

        // 创建一个目录文件夹
        IO.mkdir(tmpDir);

        // 读取文件到字符串列表
        List<String> lineList = IO.fileToStringList(nameListFile, StandardCharsets.UTF_8);
        System.out.println(lineList);

        // 将字符串写入文件
        // 这里对于content的格式做了一定要求：即最后返回的语句需要由 从文件中提取出的元素 和 连接元 拼组而成
        /**
         * List<String> strings = List.of("Java", "is", "cool"); String message =
         * String.join(" ", strings); //message returned is: "Java is cool"
         */
        //这里即是文件中的一行字符元素需要由制表符连接
        String content = String.join("\n", lineList);
        IO.stringToFile(nameListCopyFile, StandardCharsets.UTF_8, content);

    }
}
